#ifndef __ACCEPTOR_H__
#define __ACCEPTOR_H__
#include "message.h"
#include "network.h"
#include <sstream>
class Acceptor {
private:
    int id;
    std::vector<int> learners;
    Message acceptMsg;
    Message promiseMsg;
    std::shared_ptr<Network> net;

public:
    Acceptor(const int id, const std::shared_ptr<Network> &net,
             const std::initializer_list<int> &list)
        : id(id), net(net), learners(list), acceptMsg(), promiseMsg() {
        std::stringstream ss;
        ss << acceptMsg << ", " << promiseMsg << "\n";
        std::cout << ss.str();
    }
    void run() {
        for (;;) {
            std::vector<Message> msgVec;
            int ret = net->recvTcpMsg(msgVec);
            if (ret <= 0) {
                std::stringstream ss;
                ss << "Acceptor " << id << " recv failed " << ret << "\n";
                std::cout << ss.str();
                continue;
            }
            for (auto &msg : msgVec) {
                if (msg.typ == Message::msgType::Prepare) {
                    if (recevPrepare(msg) != nullptr) {
                        int ret = net->sendTcpMsg(msg);
                        if (ret > 0) {
                            promiseMsg = msg;
                        }
                        std::stringstream ss;
                        ss << "Acceptor send promise " << ret << ", " << msg
                           << "\n";
                        std::cout << ss.str();
                    } else {
                        std::stringstream ss;
                        ss << "Acceptor ignore prepare " << promiseMsg << ", "
                           << msg << "\n";
                        std::cout << ss.str();
                    }
                } else if (msg.typ == Message::msgType::Propose) {
                    bool accepted = recevPropose(msg);
                    if (accepted) {
                        for (auto learner : learners) {
                            msg.from = id;
                            msg.to = learner;
                            msg.typ = Message::msgType::Accept;
                            int ret = net->sendTcpMsg(msg);
                            std::stringstream ss;
                            ss << "Acceptor send Accept to " << ret << ", "
                               << msg << "\n";
                            std::cout << ss.str();
                        }
                    }
                } else {
                    std::stringstream ss;
                    ss << std::string(__func__) + " unsupport type " << msg
                       << "\n";
                    std::cout << ss.str();
                }
            }
        }
    }
    Message *recevPrepare(Message &prepare) {
        if (promiseMsg.seq >= prepare.seq) {
            return nullptr;
        }
        prepare.to = prepare.from;
        prepare.from = id;
        prepare.typ = Message::msgType::Promise;
        acceptMsg = prepare;
        return &prepare;
    }
    bool recevPropose(Message &proposeMsg) {
        if (acceptMsg.seq != proposeMsg.seq) {
            return false;
        }
        return true;
    }
};
#endif